package app

import (
	"fmt"
	"net"
	"sync"

	x "gitcode.com/shexk/xframe/plugin"
)

// 0为系统保留值
// const (
// 	Handle_Service = 0
// 	Handle_Plugin  = 1
// )

type App struct {
	cc        *CommandCenter
	appobj    *x.AppObj
	pluginmng *PluginManager
	udp       *Udp
	topic     *TopicMng
}

var (
	instance_app *App
	once_app     sync.Once
)

func GetApp() *App {
	once_app.Do(func() {
		// 数据总线，用于应用间通信
		GetDBCmd().OpenDB("fimq.db")
		version := GetDBCmd().ReadKeyValue("Version")
		GetLog().WriteLog(Log_Info, "System Version:"+version)

		appObj := x.NewAppObj(GetDBCmd().GetDB())
		pm := NewPluginManager(appObj)
		instance_app = &App{cc: NewCC(), appobj: appObj, pluginmng: pm, topic: NewTopic()}
	})
	return instance_app
}

func (app *App) Start() {

	//接收来自指令中心的操作
	app.udp = NewUdp("CommandCenter", 3000, app, RecvUdpCallback)
	app.udp.Start(false)

	// 加载所有插件
	app.pluginmng.LoadAllPlugin()

	go app.ProcessMsg()
}

func RecvUdpCallback(ref interface{}, addr *net.UDPAddr, data []byte, datasize int) {
	if v, ok := ref.(*App); ok {
		v.cc.ProcessCommand(addr, data, datasize)
		GetLog().WriteLog(Log_Debug, string(data))
	}
}

func (app *App) ProcessMsg() {
	//插件之间的消息管理
	for data := range app.appobj.DataBus {
		//GetLog().WriteLog(Log_Debug, "System DataBus Receive Cmd=", data.Cmd, "Option=", data.Option)
		switch data.Cmd {
		case x.Command_Exit: //退出系统
			return
		case x.Command_RegTopic: //主题操作，只有注册和反注册命令处理
			app.topic.ProcessCommand(data)
			GetLog().WriteLog(Log_Debug, string(data.Data))
		case x.Command_Result: //通过UDP发送返回操作者的结果,Option必须含有发起者的地址信息
			app.udp.SendToAddr(data.Option, data.Data, len(data.Data))
		case x.Command_DB:
			GetDBCmd().ProcessPluginMsg(data)
		case x.Command_Log:
			GetLog().WriteLog(Log_Debug, string(data.Data))
		case x.Command_TransPlugin: //插件之间的消息传递
			for v := range data.Receiver {
				switch data.Receiver[v].Type {
				case x.Type_Plugin:
					app.SendToPlugin(data.Receiver[v].Name, data)
				case x.Type_Topic:
					app.SendToTopic(data.Receiver[v].Name, data)
				case x.Type_Service: //投递给本主体程序，暂未处理
				case x.Type_Other:
				}
			}
		}
	}
}

// 发送到插件
func (app *App) SendToPlugin(pluginName string, data *x.PluginMsg) {
	if p, ok := app.pluginmng.Plugins[pluginName]; ok {
		p.Receiver(data)
	}
}

// 发送到主题
func (app *App) SendToTopic(topicName string, data *x.PluginMsg) {
	if p, ok := app.topic.TL[topicName]; ok {
		for pl := range p.PL {
			if s, k := app.pluginmng.Plugins[pl]; k {
				s.Receiver(data)
			}
		}
	} else {
		fmt.Println("No Find Topic:", topicName)
	}
}
